import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.Img;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.DES;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.liu.WarframeBotApplication;
import com.liu.common.content.RedisKeyInterface;
import com.liu.common.entity.BaseEntity;
import com.liu.common.entity.dto.WfDictDTO;
import com.liu.common.entity.qo.DeepSeekChatCompletionsQO;
import com.liu.common.entity.vo.DeepSeekChatCompletionsVO;
import com.liu.common.entity.vo.QQImageOCRVO;
import com.liu.common.entity.vo.WIAGetFissuresVO;
import com.liu.common.utils.*;
import com.liu.mybatisPlus.climbingTower.entity.base.ClimbingTowerEntityInfo;
import com.liu.mybatisPlus.climbingTower.entity.base.ClimbingTowerEntityKillReward;
import com.liu.mybatisPlus.climbingTower.service.ClimbingTowerEntityInfoService;
import com.liu.mybatisPlus.climbingTower.service.ClimbingTowerEntityKillRewardService;
import com.liu.mybatisPlus.poke.entity.base.PokeDuel;
import com.liu.mybatisPlus.poke.service.PokeDuelService;
import com.liu.mybatisPlus.wiki.entity.base.WikiRivenAttributeBasicValues;
import com.liu.mybatisPlus.wiki.service.WikiRivenAttributeBasicValuesService;
import com.liu.mybatisPlus.wm.entity.base.*;
import com.liu.mybatisPlus.wm.service.*;
import com.liu.qqRobot.event.entity.dto.EventReportingDTO;
import com.liu.qqRobot.event.service.EventService;
import com.liu.qqRobot.myself.entity.dto.ArbitrationInfoDTO;
import com.liu.qqRobot.myself.handler.JmHandler;
import com.liu.qqRobot.myself.job.ArbitrationJob;
import com.liu.qqRobot.official.job.SyncItemTendencyJob;
import com.liu.qqRobot.poke.job.SyncPokeJob;
import com.liu.qqRobot.poke.job.SyncPokeSkillJob;
import com.liu.qqRobot.q.job.SyncGroupUserJob;
import com.liu.qqRobot.wia.service.ListenInInvasionsService;
import com.liu.qqRobot.wiki.entity.dto.WikiSearchDTO;
import com.liu.qqRobot.wm.entity.dto.WarframeMarketItemsOrderTemplateDTO;
import com.liu.qqRobot.wm.entity.dto.WarframeMarketLichAuctionDTO;
import com.liu.qqRobot.wm.enums.AuctionsSortByEnum;
import com.liu.qqRobot.wm.job.SyncItemJob;
import freemarker.template.TemplateException;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.w3c.dom.Document;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.swing.Java2DRenderer;
import org.xml.sax.SAXException;

import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.net.URL;
import java.util.List;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Configuration
@RunWith(SpringRunner.class)
@SpringBootTest(classes = WarframeBotApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class ATestDemo {

    @Before
    public void setTimeZon() {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }

    public static void main(String[] args) {
//        mergeDict1();
    }

    /**
     * 合并字典
     */
    private static void mergeDict1() throws IOException {
        File file = new File("src/main/resources/dict/simplify_i18n.json");
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        StringBuilder i18n = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            i18n.append(line);
        }
        JSONArray jsonArray = JSONUtil.parseArray(i18n.toString());
        List<String> existEnNameList = new ArrayList<>();
        List<WfDictDTO> wfDictDTOS = new ArrayList<>();
        for (Object o : jsonArray) {
            WfDictDTO wfDictDTO1 = JSONUtil.toBean(JSONUtil.toJsonStr(o), WfDictDTO.class);
            if (Objects.nonNull(wfDictDTO1.getZh())) {
                if (!existEnNameList.contains(wfDictDTO1.getEn())) {
                    existEnNameList.add(wfDictDTO1.getEn());
                    WfDictDTO wfDictDTO = new WfDictDTO();
                    wfDictDTO.setEn(wfDictDTO1.getEn());
                    wfDictDTO.setZh(wfDictDTO1.getZh());
                    wfDictDTOS.add(wfDictDTO);
                }
            }
        }
        getRetain("src/main/resources/dict/WF_DICT.JSON", wfDictDTOS);
        getRetain("src/main/resources/dict/WF_INVASION.JSON", wfDictDTOS);
        getRetain("src/main/resources/dict/WF_NIGHTWAVE.JSON", wfDictDTOS);
        File saveFile = new File("src/main/resources/dict/simplify_i18n_all.json");
        cn.hutool.core.io.file.FileWriter fileWriter = FileWriter.create(saveFile);
        fileWriter.write(JSONUtil.toJsonStr(wfDictDTOS));
    }

    private static void getRetain(String filePath, List<WfDictDTO> wfDictDTOS) throws IOException {
        File file1 = new File(filePath);
        BufferedReader reader1 = new BufferedReader(new InputStreamReader(new FileInputStream(file1)));
        StringBuilder WF_DICT = new StringBuilder();
        String line1;
        while ((line1 = reader1.readLine()) != null) {
            WF_DICT.append(line1);
        }
        List<WfDictDTO> wfDictDTOS1 = JSONUtil.parseArray(WF_DICT.toString()).toList(WfDictDTO.class);
        List<String> existEnNameList = new ArrayList<>(wfDictDTOS.stream().map(WfDictDTO::getEn).toList());
        List<String> existEnNameList1 = wfDictDTOS1.stream().map(WfDictDTO::getEn).toList();
        // 获取两个字典的交集
        existEnNameList.retainAll(existEnNameList1);
        // 字典二去除交集翻译
        List<WfDictDTO> removeIntersectionList = wfDictDTOS1.stream().filter(w -> !existEnNameList.contains(w.getEn())).toList();
        wfDictDTOS.addAll(removeIntersectionList);
    }

    /**
     * 合并字典
     */
    private static void mergeDict() throws IOException {
        File file = new File("src/main/resources/dict/i18n.json");
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        StringBuilder i18n = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            i18n.append(line);
        }
        JSONObject jsonObject = JSONUtil.parseObj(i18n.toString());
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(jsonObject);
        List<String> existZHNameList = new ArrayList<>();
        List<WfDictDTO> wfDictDTOS = new ArrayList<>();
        int id = 0;
        for (Map.Entry<String, Object> stringObjectEntry : stringObjectMap.entrySet()) {
            TestA test = JSONUtil.toBean(JSONUtil.toJsonStr(stringObjectEntry.getValue()), TestA.class);
            if (Objects.nonNull(test.getZh())) {
                if (!existZHNameList.contains(test.getZh().getName()) && test.getZh().getName() != null) {
                    existZHNameList.add(test.getZh().getName());
                    WfDictDTO wfDictDTO = new WfDictDTO();
                    // 跑这个方法把id加回去
//                    wfDictDTO.setId(id);
                    wfDictDTO.setEn(test.getIt().getName());
                    wfDictDTO.setZh(test.getZh().getName());
                    wfDictDTOS.add(wfDictDTO);
                    id++;
                }
            }
        }
        File file1 = new File("src/main/resources/dict/WF_DICT.JSON");
        BufferedReader reader1 = new BufferedReader(new InputStreamReader(new FileInputStream(file1)));
        StringBuilder WF_DICT = new StringBuilder();
        String line1;
        while ((line1 = reader1.readLine()) != null) {
            WF_DICT.append(line1);
        }
        List<WfDictDTO> wfDictDTOS1 = JSONUtil.parseArray(WF_DICT.toString()).toList(WfDictDTO.class);
        List<String> existEnNameList = new ArrayList<>(wfDictDTOS.stream().map(WfDictDTO::getEn).toList());
        List<String> existEnNameList1 = wfDictDTOS1.stream().map(WfDictDTO::getEn).toList();
        // 获取两个字典的交集
        existEnNameList.retainAll(existEnNameList1);
        // 字典二去除交集翻译
        List<WfDictDTO> removeIntersectionList = wfDictDTOS1.stream().filter(w -> !existEnNameList.contains(w.getEn())).toList();
        wfDictDTOS.addAll(removeIntersectionList);
        // id重排
        id = 0;
        for (WfDictDTO wfDictDTO : wfDictDTOS) {
            // 跑这个方法把id加回去
//            wfDictDTO.setId(id);
            id++;
        }
        File saveFile = new File("src/main/resources/dict/simplify_i18n.json");
        cn.hutool.core.io.file.FileWriter fileWriter = FileWriter.create(saveFile);
        fileWriter.write(JSONUtil.toJsonStr(wfDictDTOS));
    }

    @Getter
    @Setter
    public static class TestA extends BaseEntity {
        private ZH zh;
        private IT it;
        @Getter
        @Setter
        public static class ZH extends BaseEntity {
            private String name;
        }
        @Getter
        @Setter
        public static class IT extends BaseEntity {
            private String name;
        }
    }

    @Resource
    private SyncItemJob syncItemJob;

    @Test
    public void testSyncItemJob() {
        syncItemJob.syncItem();
//        syncItemJob.syncLich();
//        syncItemJob.syncSister();
//        syncItemJob.syncRiven();
    }

    @Test
    public void testHtml2Png() throws IOException, TemplateException, ParserConfigurationException, SAXException {
        long timeMillis = System.currentTimeMillis();
        HtmlToImageUtils.htmlToImage("wfHelp.html", null, "src/main/resources/picture/wfHelp.png", 3000);
        System.out.println(System.currentTimeMillis() - timeMillis);
    }

    @Test
    public void testNotFunUri() {
        WikiSearchDTO wikiSearchDTO = WikiClientUtils.search("花");
        if (wikiSearchDTO != null) {
            log.info(wikiSearchDTO.toString());
        }
    }

    @Test
    public void test() {
        List<WarframeMarketLichAuctionDTO> LichAuctions = WmClientUtils.getLichAuctions("lich", null, "kuva_sobek", "cold", null, null, null, null, AuctionsSortByEnum.PRICE_ASC.getType());
        log.info(LichAuctions.toString());
    }

    @Test
    public void testHtmlHeight() throws TemplateException, IOException, ParserConfigurationException, SAXException {
        Map<String, Object> templateParam = new HashMap<>();
        templateParam.put("param", "111");
        templateParam.put("itemName", "111");
        List<WarframeMarketItemsOrderTemplateDTO> warframeMarketItemsOrderTemplateDTOS = new ArrayList<>();
//        for (int i = 0; i < 5; i++) {
//            WarframeMarketItemsOrderTemplateDTO warframeMarketItemsOrderTemplateDTO = new WarframeMarketItemsOrderTemplateDTO();
//            warframeMarketItemsOrderTemplateDTO.setIngameName(String.valueOf(i));
//            warframeMarketItemsOrderTemplateDTO.setModRank(String.valueOf(i));
//            warframeMarketItemsOrderTemplateDTO.setQuantity(String.valueOf(i));
//            warframeMarketItemsOrderTemplateDTO.setPlatinum(String.valueOf(i));
//            warframeMarketItemsOrderTemplateDTO.setStatus(String.valueOf(i));
//            warframeMarketItemsOrderTemplateDTOS.add(warframeMarketItemsOrderTemplateDTO);
//        }
        templateParam.put("orderList", warframeMarketItemsOrderTemplateDTOS);
        HtmlToImageUtils.htmlToImage("orderTemplate.html", templateParam, "src/main/resources/picture/order.png", 2200);
    }

    @Resource
    private WmRivenListenService wmRivenListenService;

    @Test
    public void testWmRiven() {
        WmRivenListen wmRivenListen = new WmRivenListen();
        wmRivenListen.setUserId(1L);
        wmRivenListen.setGroupId(1L);
        wmRivenListen.setParam("1");
        wmRivenListenService.save(wmRivenListen);
    }

    @Resource
    private WikiRivenAttributeBasicValuesService wikiRivenAttributeBasicValuesService;

    @Resource
    private WmRivenItemService wmRivenItemService;

    @Test
    public void testReadPicture() {
        Pattern r = Pattern.compile("[0-9.]+");
        List<WmRivenItem> wmRivenItems = wmRivenItemService.list();
        List<String> itemNameList = wmRivenItems.stream().map(WmRivenItem::getItemName).toList();
        List<WikiRivenAttributeBasicValues> wikiRivenAttributeBasicValues = wikiRivenAttributeBasicValuesService.list();
        List<String> nameList = wikiRivenAttributeBasicValues.stream().map(WikiRivenAttributeBasicValues::getName).toList();
        QQImageOCRVO qqImageOCRVO = QQClientUtils.OCR("src/main/resources/rivenPicture/page_1.png");
        List<QQImageOCRVO.Data.Text> textList = qqImageOCRVO.getData().getTexts();
        List<String> positiveStatsList = new ArrayList<>();
        List<String> negativeStatsList = new ArrayList<>();
        String itemName = "冰凇";
        for (QQImageOCRVO.Data.Text text : textList) {
            String words = text.getText();
            for (String name : itemNameList) {
                if (words.contains(name)) {
                    itemName = name;
                }
            }
            for (String name : nameList) {
                if (words.contains(name)) {
                    if (words.contains("+")) {
                        words = words.replace("+", "").replace(name, "");
                        Matcher wordsMatcher = r.matcher(words);
                        if (wordsMatcher.find()) {
                            positiveStatsList.add(wordsMatcher.group() + " " + name);
                        }
                    } else if (words.contains("-")) {
                        words = words.replace("-", "").replace(name, "");
                        Matcher wordsMatcher = r.matcher(words);
                        if (wordsMatcher.find()) {
                            negativeStatsList.add(wordsMatcher.group() + " " + name);
                        }
                    }
                    break;
                }
            }
        }
        System.out.println(itemName);
        System.out.println(positiveStatsList);
        System.out.println(negativeStatsList);
    }

    @Test
    public void testCutPicture() {
        File file1 = new File("src/main/resources/rivenPicture/riven.png");
        if (!file1.exists()) {
            file1.mkdirs();
        }
        Rectangle rectangle = new Rectangle(5, 90,275, 125);
        Img.from(new File("src/main/resources/rivenPicture/riven1.jpg"))
                .cut(rectangle)
                .write(file1);
        ImgUtil.scale(file1, file1, 2F);
        this.testReadPicture();
    }

    @Test
    public void testGetRivenTendency() {
        List<Map<String, BigDecimal>> resultList = new ArrayList<>();
        String body = HttpRequest.get("https://warframe.fandom.com/wiki/Riven_Mods/Weapon_Dispos/All?action=render")
                .execute()
                .body();
        Pattern firstPattern = Pattern.compile("(?<=<li><a href=\"https://warframe.fandom.com/wiki/).+(?=</li>)");
        Matcher firstMatcher = firstPattern.matcher(body);
        while (firstMatcher.find()) {
            Map<String, BigDecimal> result = new HashMap<>();
            resultList.add(result);
            String firstGroup = firstMatcher.group();
            Pattern namePattern = Pattern.compile("(?<=\">).+(?=</a>)");
            Matcher nameMatcher = namePattern.matcher(firstGroup);
            String name = null;
            if (nameMatcher.find()) {
                name = nameMatcher.group();
            }
            Pattern valuePattern = Pattern.compile("(?<=</a> \\().+(?=\\))");
            Matcher valueMatcher = valuePattern.matcher(firstGroup);
            BigDecimal value = null;
            if (valueMatcher.find()) {
                value = new BigDecimal(valueMatcher.group());
            }
            result.put(name, value);
        }
        System.out.println(resultList);
    }

    @Resource
    private SyncItemTendencyJob syncItemTendencyJob;

    @Test
    public void testSyncItemTendency() {
        syncItemTendencyJob.syncItemTendency();
    }

    @Test
    public void testCalRiven() {
        // 公式参考 https://warframe.huijiwiki.com/wiki/%E8%A3%82%E7%BD%85MOD
        BigDecimal multiply1 = new BigDecimal("0.9").multiply(new BigDecimal("1.2")).multiply(new BigDecimal("1.3")).multiply(new BigDecimal("0.9375"));
        System.out.println(multiply1);
        BigDecimal multiply2 = new BigDecimal("1.1").multiply(new BigDecimal("1.2")).multiply(new BigDecimal("1.3")).multiply(new BigDecimal("0.9375"));
        System.out.println(multiply2);
        BigDecimal multiply3 = new BigDecimal("1").multiply(new BigDecimal("1.2")).multiply(new BigDecimal("1.3")).multiply(new BigDecimal("0.9375"));
        System.out.println(multiply3.subtract(new BigDecimal("1.302")));
    }

    @Test
    public void testPrivateMsg() {
        QQClientUtils.sendMsg("111", 1803384152L, null, false);
    }

    @Test
    public void genIamge() throws IOException, ParserConfigurationException, SAXException {
        String html = "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\"></meta>\n" +
                "    <title>紫卡拍卖</title>\n" +
                "</head>\n" +
                "<body style=\"background-color: black;\">\n" +
                "<div style=\"border: black 2px solid;background-color: #ffffff;border-radius: 25px;display: flex;align-content: center;justify-content: center;\">\n" +
                "  <table>\n" +
                "    <tr>\n" +
                "      <td style=\"text-align: center;width:550px;font-size: 30px;\">\n" +
                "        以下是出售【<strong style=\"color: #0051ff;\">弧电离子枪</strong>】紫卡<br></br>\n" +
                "        【<strong style=\"color: #0051ff;\">弧电离子枪</strong>】紫卡的：\n" +
                "      </td>\n" +
                "    </tr>\n" +
                "    <tr>\n" +
                "      <td>\n" +
                "        <ul>\n" +
                "          <li style=\"font-size: 20px;\">\n" +
                "            【<strong style=\"color: #24bd24;\">Crstalcr</strong>】 - 游戏中<br></br>\n" +
                "            【<strong style=\"color: #043eff;\">弧电离子枪</strong>】 【<strong style=\"color: #24bd24;\">0</strong>】级 【<strong style=\"color: #24bd24;\">8</strong>】段 【<strong style=\"color: #24bd24;\">0</strong>】洗 【<strong style=\"color: #24bd24;\">vazarin</strong>】槽<br></br>\n" +
                "            <strong style=\"color: #24bd24;\">正面属性</strong>：+穿透0.20|+毒素伤害6.90%|+触发时间7.80%|<br></br>\n" +
                "            \n" +
                "            起拍价：【<strong style=\"color: #043eff;\">20</strong>】  一口价：【<strong style=\"color: #043eff;\">20</strong>】  最高出价：【<strong style=\"color: #043eff;\">暂无</strong>】\n" +
                "          </li>\n" +
                "          <li style=\"font-size: 20px;\">\n" +
                "            【<strong style=\"color: #24bd24;\">aimobenmo</strong>】 - 游戏中<br></br>\n" +
                "            【<strong style=\"color: #043eff;\">弧电离子枪</strong>】 【<strong style=\"color: #24bd24;\">0</strong>】级 【<strong style=\"color: #24bd24;\">12</strong>】段 【<strong style=\"color: #24bd24;\">0</strong>】洗 【<strong style=\"color: #24bd24;\">madurai</strong>】槽<br></br>\n" +
                "            <strong style=\"color: #24bd24;\">正面属性</strong>：+电击伤害10.30%|+触发时间10.60%|<br></br>\n" +
                "            \n" +
                "            起拍价：【<strong style=\"color: #043eff;\">30</strong>】  一口价：【<strong style=\"color: #043eff;\">30</strong>】  最高出价：【<strong style=\"color: #043eff;\">暂无</strong>】\n" +
                "          </li>\n" +
                "          <li style=\"font-size: 20px;\">\n" +
                "            【<strong style=\"color: #24bd24;\">ItsTheInternet</strong>】 - 游戏中<br></br>\n" +
                "            【<strong style=\"color: #043eff;\">弧电离子枪</strong>】 【<strong style=\"color: #24bd24;\">0</strong>】级 【<strong style=\"color: #24bd24;\">15</strong>】段 【<strong style=\"color: #24bd24;\">0</strong>】洗 【<strong style=\"color: #24bd24;\">naramon</strong>】槽<br></br>\n" +
                "            <strong style=\"color: #24bd24;\">正面属性</strong>：+对Corpus伤害X1.06|+电击伤害11.00%|<br></br>\n" +
                "            <strong style=\"color: #24bd24;\">负面属性</strong>：-多重射击-5.70%|<br></br>\n" +
                "            起拍价：【<strong style=\"color: #043eff;\">40</strong>】  一口价：【<strong style=\"color: #043eff;\">40</strong>】  最高出价：【<strong style=\"color: #043eff;\">暂无</strong>】\n" +
                "          </li>\n" +
                "          <li style=\"font-size: 20px;\">\n" +
                "            【<strong style=\"color: #24bd24;\">XxPERFORATORxX</strong>】 - 游戏中<br></br>\n" +
                "            【<strong style=\"color: #043eff;\">弧电离子枪</strong>】 【<strong style=\"color: #24bd24;\">0</strong>】级 【<strong style=\"color: #24bd24;\">16</strong>】段 【<strong style=\"color: #24bd24;\">0</strong>】洗 【<strong style=\"color: #24bd24;\">vazarin</strong>】槽<br></br>\n" +
                "            <strong style=\"color: #24bd24;\">正面属性</strong>：+毒素伤害12.30%|+后坐力-10.60%|<br></br>\n" +
                "            <strong style=\"color: #24bd24;\">负面属性</strong>：-弹匣容量-2.50%|<br></br>\n" +
                "            起拍价：【<strong style=\"color: #043eff;\">50</strong>】  一口价：【<strong style=\"color: #043eff;\">50</strong>】  最高出价：【<strong style=\"color: #043eff;\">暂无</strong>】\n" +
                "          </li>\n" +
                "          <li style=\"font-size: 20px;\">\n" +
                "            【<strong style=\"color: #24bd24;\">BunnyWa1ker</strong>】 - 游戏中<br></br>\n" +
                "            【<strong style=\"color: #043eff;\">弧电离子枪</strong>】 【<strong style=\"color: #24bd24;\">0</strong>】级 【<strong style=\"color: #24bd24;\">11</strong>】段 【<strong style=\"color: #24bd24;\">1</strong>】洗 【<strong style=\"color: #24bd24;\">naramon</strong>】槽<br></br>\n" +
                "            <strong style=\"color: #24bd24;\">正面属性</strong>：+后坐力-7.50%|+对Corpus伤害X1.04|+多重射击8.80%|<br></br>\n" +
                "            \n" +
                "            起拍价：【<strong style=\"color: #043eff;\">70</strong>】  一口价：【<strong style=\"color: #043eff;\">70</strong>】  最高出价：【<strong style=\"color: #043eff;\">暂无</strong>】\n" +
                "          </li>\n" +
                "        </ul>\n" +
                "      </td>\n" +
                "    </tr>\n" +
                "  </table>\n" +
                "</div>\n" +
                "</body>\n" +
                "</html>";
        System.out.println(html);
        ByteArrayInputStream bin = new ByteArrayInputStream(html.getBytes());
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(bin);
        Java2DRenderer renderer = new Java2DRenderer(document, 2000, -1);
        SharedContext sharedContext = renderer.getSharedContext();
        sharedContext.setDotsPerPixel(3);
        sharedContext.setDPI(523);
        BufferedImage image = renderer.getImage();
        File file = new File("src/main/resources/picture/rivenAuction.png");
        if (!file.exists()) {
            file.mkdirs();
        }
        ImageIO.write(image, "png", file);
    }

    @Test
    public void testGetPoke() throws IOException {
        List<String> regionList = Arrays.asList("关都", "城都", "丰缘", "神奧", "合眾", "卡洛斯", "阿羅拉", "伽勒尔", "帕底亚");
        String url = "https://wiki.52poke.com/wiki/%E5%AE%9D%E5%8F%AF%E6%A2%A6%E5%88%97%E8%A1%A8%EF%BC%88%E6%8C%89%E5%85%A8%E5%9B%BD%E5%9B%BE%E9%89%B4%E7%BC%96%E5%8F%B7%EF%BC%89";
        Connection connect = Jsoup.connect(url);
        Element body = connect.get().body();
        List<Map<String, String>> pokeMapList = new ArrayList<>();
        regionList.forEach(region -> {
            Elements select = body.select("table.roundy.eplist.s-" + region + ".sortable.rdexn");
            Element element = select.get(0);
            Elements tbody = element.getElementsByTag("tbody");
            Element element1 = tbody.get(0);
            Elements tr = element1.getElementsByTag("tr");
            for (Element element2 : tr) {
                Elements td = element2.getElementsByTag("td");
                if (td != null) {
                    Map<String, String> pokeMap = new HashMap<>();
                    for (int i = 0; i < td.size(); i++) {
                        Element element3 = td.get(i);
                        if (i == 0) {
                            String text = element3.text().replace("#", "");
                            pokeMap.put("id", text);
                        }
                        if (i == 3) {
                            String text = element3.getElementsByTag("a").text();
                            pokeMap.put("name", text);
                        }
                        if (i == 6) {
                            String text = element3.getElementsByTag("a").text();
                            pokeMap.put("attribute1", text);
                        }
                        if (i == 7) {
                            String text = element3.getElementsByTag("a").text();
                            pokeMap.put("attribute2", text);
                        }
                    }
                    if (MapUtil.isNotEmpty(pokeMap)) {
                        pokeMapList.add(pokeMap);
                    }
                }
            }
        });
        System.out.println(pokeMapList);
    }

    @Test
    public void testPokeEnName() throws IOException {
        String url = "https://wiki.52poke.com/wiki/%E5%AE%9D%E5%8F%AF%E6%A2%A6%E5%88%97%E8%A1%A8%EF%BC%88%E6%8C%89%E5%85%A8%E5%9B%BD%E5%9B%BE%E9%89%B4%E7%BC%96%E5%8F%B7%EF%BC%89";
        Connection connect = Jsoup.connect(url);
        String text = connect.get().body().getElementsByClass("rdexn-enname").text();
        System.out.println(text);
    }

    @Test
    public void testPokeIamge() throws IOException {
        String detailUrl = "https://wiki.52poke.com/wiki/File:001Bulbasaur.png";
        Connection detailConnect = Jsoup.connect(detailUrl);
        Elements fullImageLinkElements = detailConnect.get().getElementsByClass("fullImageLink");
        Element element5 = fullImageLinkElements.get(0);
        String href = element5.getElementsByTag("a").attr("href");
        String imgUrl = href.replace("//", "https://");
        System.out.println(imgUrl);
        Pattern imgPattern = Pattern.compile("(?<=<a href=\").+(?=\"><i)");
        Matcher imgMatcher = imgPattern.matcher(fullImageLinkElements.html());
        if (imgMatcher.find()) {
            System.out.println(imgMatcher.group().replaceAll("//", "https://"));
        }
    }

    @Resource
    private SyncPokeJob syncPokeJob;

    @Test
    public void testSyncPoke() {
        syncPokeJob.syncPoke();
    }

    @Resource
    private SyncGroupUserJob syncGroupUserJob;

    @Test
    public void testGetGroupUser() {
        syncGroupUserJob.syncGroupUser();
    }

    @Test
    public void testGetPokeSkill() throws IOException {
        List<String> regionList = Arrays.asList("关都", "城都", "丰缘", "神奥", "合众", "卡洛斯", "阿罗拉", "伽勒尔", "帕底亚");
        String url = "https://wiki.52poke.com/wiki/%E6%8B%9B%E5%BC%8F%E5%88%97%E8%A1%A8";
        Connection connect = Jsoup.connect(url);
        Element body = connect.get().body();
        List<Map<String, String>> skillMapList = new ArrayList<>();
        regionList.forEach(region -> {
            Elements select = body.select("table.hvlist.a-c.roundy.bg-" + region + ".bd-" + region + ".sortable.fulltable");
            Element element = select.get(0);
            Elements tbody = element.getElementsByTag("tbody");
            Element element1 = tbody.get(0);
            Elements tr = element1.getElementsByTag("tr");
            for (Element element2 : tr) {
                Elements td = element2.getElementsByTag("td");
                if (td != null) {
                    Map<String, String> skillMap = new HashMap<>();
                    for (int i = 0; i < td.size(); i++) {
                        Element element3 = td.get(i);
                        if (i == 0) {
                            String text = element3.text();
                            skillMap.put("wikiId", text);
                        }
                        if (i == 1) {
                            String text = element3.getElementsByTag("a").text();
                            skillMap.put("name", text);
                        }
                        if (i == 4) {
                            String text = element3.getElementsByTag("a").text();
                            skillMap.put("attribute", text);
                        }
                        if (i == 5) {
                            String text = element3.getElementsByTag("a").text();
                            skillMap.put("classification", text);
                        }
                    }
                    if (MapUtil.isNotEmpty(skillMap)) {
                        skillMapList.add(skillMap);
                    }
                }
            }
        });
        System.out.println(skillMapList);
    }

    @Resource
    private SyncPokeSkillJob syncPokeSkillJob;

    @Test
    public void testSyncPokeSkill() {
        syncPokeSkillJob.syncPokeSkill();
    }

    @Test
    public void testSavePokeImageToLocal() throws IOException {
        String imageUrl = "https://media.52poke.com/wiki/d/d1/012Butterfree.png";
        String[] split = imageUrl.split("/");
        int length = split.length;
        String s = split[length - 1];
        System.out.println(s);
        String localUrl = "src/main/resources/pokeImage/" + s;
        File file = new File(localUrl);
        if (!file.exists()) {
            file.mkdirs();
        }
        InputStream inputStream = new URL(imageUrl).openConnection().getInputStream();
        BufferedImage bufferedImage = ImgUtil.read(inputStream);
        ImageIO.write(bufferedImage, "png", file);
    }



    @Resource
    PokeDuelService pokeDuelService;

    @Test
    public void testMyBatisPlus() {
        QueryWrapper<PokeDuel> pokeDuelQueryWrapper = new QueryWrapper<>();
        pokeDuelQueryWrapper.and(wrapper1 -> {
            wrapper1.and(wrapper2 -> {
                wrapper2.eq("group1_id", 424907162);
                wrapper2.eq("user1_id", 1803384152);
            }).or(wrapper2 -> {
                wrapper2.eq("group2_id", 424907162);
                wrapper2.eq("user2_id", 1803384152);
            });
        });
        pokeDuelQueryWrapper.in("status", Arrays.asList(0, 1));
        List<PokeDuel> pokeDuelList = pokeDuelService.list(pokeDuelQueryWrapper);
    }



    @Resource
    private EventService eventService;

    @Test
    public void testEvent() {
        String json = "{\n" +
                "  \"self_id\": 675080584,\n" +
                "  \"user_id\": 1803384152,\n" +
                "  \"time\": 1738979265,\n" +
                "  \"message_id\": 1004147295,\n" +
                "  \"message_seq\": 3296708,\n" +
                "  \"message_type\": \"group\",\n" +
                "  \"sender\": {\n" +
                "    \"user_id\": 1803384152,\n" +
                "    \"nickname\": \"空亦是满\",\n" +
                "    \"card\": \"GaryLiuCL 永远18段~\",\n" +
                "    \"role\": \"member\",\n" +
                "    \"title\": \"\"\n" +
                "  },\n" +
                "  \"raw_message\": \"[CQ:image,file=54678FC24BEF7F549F8640B5BDF7C10A.png,subType=0,url=https://multimedia.nt.qq.com.cn/download?appid=1407&amp;fileid=EhR2B0dJ6e4Aa1cavmVH5L-PiDjh8RiXoggg_wooyNfIyvqyiwMyBHByb2RQgL2jAVoQbvUCQFS2wHdReH0Eu2o7RQ&amp;spec=0&amp;rkey=CAISKKSBekjVG1fMRrkWD6GRecVPfUrs8YMMfe2W0HaOAeOIVnSoL9VBqdQ,file_size=135447]ra 三宝聚\",\n" +
                "  \"font\": 14,\n" +
                "  \"sub_type\": \"normal\",\n" +
                "  \"message\": [\n" +
                "    {\n" +
                "      \"type\": \"image\",\n" +
                "      \"data\": {\n" +
                "        \"file\": \"54678FC24BEF7F549F8640B5BDF7C10A.png\",\n" +
                "        \"subType\": 0,\n" +
                "        \"url\": \"https://multimedia.nt.qq.com.cn/download?appid=1407&fileid=EhR2B0dJ6e4Aa1cavmVH5L-PiDjh8RiXoggg_wooyNfIyvqyiwMyBHByb2RQgL2jAVoQbvUCQFS2wHdReH0Eu2o7RQ&spec=0&rkey=CAISKKSBekjVG1fMRrkWD6GRecVPfUrs8YMMfe2W0HaOAeOIVnSoL9VBqdQ\",\n" +
                "        \"file_size\": \"135447\"\n" +
                "      }\n" +
                "    },\n" +
                "    {\n" +
                "      \"type\": \"text\",\n" +
                "      \"data\": {\n" +
                "        \"text\": \"ra 三宝聚\"\n" +
                "      }\n" +
                "    }\n" +
                "  ],\n" +
                "  \"message_format\": \"array\",\n" +
                "  \"post_type\": \"message\",\n" +
                "  \"group_id\": 424907162\n" +
                "}";
        eventService.handleEvent(JSONUtil.toBean(json, EventReportingDTO.class));
    }


    @Test
    public void testImageOCR() {
        File file = new File("src/main/resources/rivenPicture/riven.png");
        String encode = Base64.encode(file);
        Map<String, String> body = new HashMap<>();
        body.put("image", "base64://" + encode);
        HttpResponse execute = HttpRequest.post("http://localhost:3000/ocr_image")
                .header("Content-Type", ContentType.JSON.getValue())
                .body(JSONUtil.toJsonStr(body))
                .execute();
        System.out.println(execute.body());
    }



    @Resource
    private ListenInInvasionsService listenInInvasionsService;

    @Test
    public void testListenInInvasions() {
        listenInInvasionsService.listenIn();
    }

    @Resource
    private WmRivenItemKeyWordService wmRivenItemKeyWordService;

    @Resource
    private WmRivenAttributesService wmRivenAttributesService;

    @Resource
    private WmRivenAttributesKeyWordService wmRivenAttributesKeyWordService;

    @Test
    public void testInitWmr() {
        String text = "wmr 暴击 暴伤 多重 负变焦 托里德";
        String[] textSplit = text.split(" ");
        // 获取需要查询紫卡信息的物品名称
        WmRivenItem wmRivenItem = null;
        String itemName = textSplit[textSplit.length - 1];
        QueryWrapper<WmRivenItemKeyWord> wmRivenKeyWordQueryWrapper = new QueryWrapper<>();
        wmRivenKeyWordQueryWrapper.eq("key_word", itemName);
        WmRivenItemKeyWord wmRivenItemKeyWord = wmRivenItemKeyWordService.getOne(wmRivenKeyWordQueryWrapper);
        if (wmRivenItemKeyWord != null) {
            wmRivenItem = wmRivenItemService.getById(wmRivenItemKeyWord.getId());
        } else {
            QueryWrapper<WmRivenItem> wmRivenItemQueryWrapper = new QueryWrapper<>();
            wmRivenItemQueryWrapper.eq("item_name", itemName);
            wmRivenItem = wmRivenItemService.getOne(wmRivenItemQueryWrapper);
        }
        if (wmRivenItem == null) {
            return;
        }

        // 获取需要查询的正/负向属性
        List<String> attributesList = new ArrayList<>();
        for (int i = 0; i < textSplit.length; i++) {
            if (i != 0 && i < textSplit.length - 1) {
                attributesList.add(textSplit[i]);
            }
        }
        List<String> positiveStatsList = new ArrayList<>(3);
        List<String> negativeStatsList = new ArrayList<>(3);
        List<WmRivenAttributesKeyWord> wmRivenAttributesKeyWords = wmRivenAttributesKeyWordService.list();
        Map<String, String> wmRivenAttributesKeyWordMap = wmRivenAttributesKeyWords.stream().collect(Collectors.toMap(WmRivenAttributesKeyWord::getKeyWord, WmRivenAttributesKeyWord::getId));
        attributesList.forEach(attributes -> {
            WmRivenAttributes wmRivenAttributes;
            if (attributes.contains("负")) {
                attributes = attributes.replace("负", "");
                String attributesId = wmRivenAttributesKeyWordMap.get(attributes);
                if (attributesId == null) {
                    QueryWrapper<WmRivenAttributes> wmRivenAttributesQueryWrapper = new QueryWrapper<>();
                    wmRivenAttributesQueryWrapper.eq("effect", attributes);
                    wmRivenAttributes = wmRivenAttributesService.getOne(wmRivenAttributesQueryWrapper);
                } else {
                    wmRivenAttributes = wmRivenAttributesService.getById(attributesId);
                }
                if (wmRivenAttributes != null) {
                    negativeStatsList.add(wmRivenAttributes.getUrlName());
                }
            } else {
                String attributesId = wmRivenAttributesKeyWordMap.get(attributes);
                if (attributesId == null) {
                    QueryWrapper<WmRivenAttributes> wmRivenAttributesQueryWrapper = new QueryWrapper<>();
                    wmRivenAttributesQueryWrapper.eq("effect", attributes);
                    wmRivenAttributes = wmRivenAttributesService.getOne(wmRivenAttributesQueryWrapper);
                } else {
                    wmRivenAttributes = wmRivenAttributesService.getById(attributesId);
                }
                if (wmRivenAttributes != null) {
                    positiveStatsList.add(wmRivenAttributes.getUrlName());
                }
            }
        });
        System.out.println(wmRivenItem);
        System.out.println(negativeStatsList);
        System.out.println(positiveStatsList);
    }

    @Test
    public void testDateUtil() {
        int thisYear = DateUtil.thisYear();
        int thisMonth = DateUtil.thisMonth();
        int lastYear = thisYear - 1;
        for (int i = 1; i <= 12; i++) {
            String month;
            if (i >= 10) {
                month = lastYear + "-" + i + "-01 00:00:00";
            } else {
                month = lastYear + "-0" + i + "-01 00:00:00";
            }
            DateTime endOfMonth = DateUtil.offsetHour(DateUtil.endOfMonth(DateUtil.parseDate(month)), -8);
            DateTime beginOfMonth = DateUtil.offsetHour(DateUtil.beginOfMonth(DateUtil.parseDate(month)), -8);
            System.out.println(beginOfMonth);
            System.out.println(endOfMonth);
        }

    }

    @Test
    public void testHtmlTemplate() throws TemplateException, IOException, ParserConfigurationException, SAXException, ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Map<String, Object> templateParam = new HashMap<>();
        File file = new File("src/main/resources/backgroundImage/backgroundImage3.png");
        String encode = Base64.encode(file);
        templateParam.put("encode", encode);
        List<WIAGetFissuresVO> wiaGetFissuresVOList = WIAClientUtils.getFissures();
        wiaGetFissuresVOList = wiaGetFissuresVOList.stream()
                .filter(w -> !w.getIsHard() && !w.getIsStorm() && w.getActive())
                .collect(Collectors.toList());
        Map<String, List<WIAGetFissuresVO>> groupByTier = wiaGetFissuresVOList.stream().collect(Collectors.groupingBy(WIAGetFissuresVO::getTier));
        List<Object> tierList = new ArrayList<>();
        for (Map.Entry<String, List<WIAGetFissuresVO>> entry : groupByTier.entrySet()) {
            List<WIAGetFissuresVO> wiaGetFissuresVOS = entry.getValue();
            String tier = entry.getKey();
            Map<String, Object> tierListParam = new HashMap<>();
            tierListParam.put("tier", tier);
            tierListParam.put("wiaGetFissuresVOS", wiaGetFissuresVOS);
            tierList.add(tierListParam);
        }
        templateParam.put("tierList", tierList);
        HtmlToImageUtils.htmlToImage("testDemo.html", templateParam,
                "src/main/resources/picture/testDemo.png", 2000);
    }



    @Resource
    private ClimbingTowerEntityInfoService climbingTowerEntityInfoService;

    @Resource
    private ClimbingTowerEntityKillRewardService climbingTowerEntityKillRewardService;

    @Test
    public void testInsertMonster() {
        List<ClimbingTowerEntityInfo> climbingTowerEntityInfos = new ArrayList<>();
        ClimbingTowerEntityInfo climbingTowerEntityInfo = new ClimbingTowerEntityInfo();
        climbingTowerEntityInfo.setName("迷雾蛙");
        climbingTowerEntityInfo.setEntityType("monster");
        climbingTowerEntityInfo.setGrade(1);
        climbingTowerEntityInfo.setHp(3);
        climbingTowerEntityInfo.setAggressivity(1);
        climbingTowerEntityInfos.add(climbingTowerEntityInfo);
        climbingTowerEntityInfo = new ClimbingTowerEntityInfo();
        climbingTowerEntityInfo.setName("树影鼠");
        climbingTowerEntityInfo.setEntityType("monster");
        climbingTowerEntityInfo.setGrade(1);
        climbingTowerEntityInfo.setHp(4);
        climbingTowerEntityInfo.setAggressivity(2);
        climbingTowerEntityInfos.add(climbingTowerEntityInfo);
        climbingTowerEntityInfo = new ClimbingTowerEntityInfo();
        climbingTowerEntityInfo.setName("岩石蝎");
        climbingTowerEntityInfo.setEntityType("monster");
        climbingTowerEntityInfo.setGrade(1);
        climbingTowerEntityInfo.setHp(3);
        climbingTowerEntityInfo.setAggressivity(2);
        climbingTowerEntityInfos.add(climbingTowerEntityInfo);
        climbingTowerEntityInfo = new ClimbingTowerEntityInfo();
        climbingTowerEntityInfo.setName("薄雾蝶");
        climbingTowerEntityInfo.setEntityType("monster");
        climbingTowerEntityInfo.setGrade(1);
        climbingTowerEntityInfo.setHp(3);
        climbingTowerEntityInfo.setAggressivity(1);
        climbingTowerEntityInfos.add(climbingTowerEntityInfo);
        climbingTowerEntityInfo = new ClimbingTowerEntityInfo();
        climbingTowerEntityInfo.setName("幽林鹿");
        climbingTowerEntityInfo.setEntityType("monster");
        climbingTowerEntityInfo.setGrade(1);
        climbingTowerEntityInfo.setHp(6);
        climbingTowerEntityInfo.setAggressivity(3);
        climbingTowerEntityInfos.add(climbingTowerEntityInfo);
        climbingTowerEntityInfo = new ClimbingTowerEntityInfo();
        climbingTowerEntityInfo.setName("沼泽鳄");
        climbingTowerEntityInfo.setEntityType("monster");
        climbingTowerEntityInfo.setGrade(1);
        climbingTowerEntityInfo.setHp(8);
        climbingTowerEntityInfo.setAggressivity(4);
        climbingTowerEntityInfos.add(climbingTowerEntityInfo);
        climbingTowerEntityInfoService.saveBatch(climbingTowerEntityInfos);
        List<ClimbingTowerEntityKillReward> climbingTowerEntityKillRewards = new ArrayList<>();
        for (ClimbingTowerEntityInfo towerEntityInfo : climbingTowerEntityInfos) {
            ClimbingTowerEntityKillReward climbingTowerEntityKillReward = new ClimbingTowerEntityKillReward();
            climbingTowerEntityKillReward.setEntityId(towerEntityInfo.getId());
            climbingTowerEntityKillReward.setKey("experience");
            climbingTowerEntityKillReward.setValue("4");
            climbingTowerEntityKillRewards.add(climbingTowerEntityKillReward);
            climbingTowerEntityKillReward = new ClimbingTowerEntityKillReward();
            climbingTowerEntityKillReward.setEntityId(towerEntityInfo.getId());
            climbingTowerEntityKillReward.setKey("species");
            climbingTowerEntityKillReward.setValue("4");
            climbingTowerEntityKillRewards.add(climbingTowerEntityKillReward);
        }
        climbingTowerEntityKillRewardService.saveBatch(climbingTowerEntityKillRewards);
    }

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void testCrypto() {
        // 获取随机uuid
        String uuid = UUID.randomUUID().toString(true);
        System.out.println(uuid);
        // uuid保存到redis
        redisTemplate.opsForValue().set(RedisKeyInterface.DEEPSEEK_APIKEY_ENCRYPTION_UUID_REDIS_KEY, uuid);
        DES des = SecureUtil.des(uuid.getBytes());
        // 需要加密的数据
        String apiKey = "";
        // 加密
        String encryptHex = des.encryptHex(apiKey);
        // 密文保存到redis
        redisTemplate.opsForValue().set(RedisKeyInterface.DEEPSEEK_APIKEY_ENCRYPTION_ENCRYPTHEX_REDIS_KEY, encryptHex);
        System.out.println(encryptHex);
    }

    @Test
    public void testDeepSeek() {
        DeepSeekChatCompletionsQO deepSeekChatCompletionsQO = new DeepSeekChatCompletionsQO();
        List<DeepSeekChatCompletionsQO.Message> messages = new ArrayList<>();
        DeepSeekChatCompletionsQO.Message message = new DeepSeekChatCompletionsQO.Message();
        message.setRole("user");
        message.setContent("你好DeepSeek，给我讲个笑话");
        messages.add(message);
        deepSeekChatCompletionsQO.setMessages(messages);
        System.out.println(deepSeekChatCompletionsQO);
        DeepSeekChatCompletionsVO deepSeekChatCompletionsVO = DeepSeekClientUtils.getChatCompletions(deepSeekChatCompletionsQO);
//        DeepSeekChatCompletionsVO deepSeekChatCompletionsVO = JSONUtil.parseObj("{\"id\":\"faed6326-be6c-4447-a9b9-0b72b9246b99\",\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"message\":{\"content\":\"以下是《Warframe》中执法者（Kuva Hek）的两种常见高伤害配卡方案，兼顾不同场景需求。配卡会根据你的段位和Mod等级调整，建议先极化2-3次（V和-极性）：\\n\\n---\\n\\n### **基础暴击流（高爆发秒杀）**\\n**核心Mod**（必选）：\\n1. **地狱弹膛**（+120%基础伤害）  \\n2. **白霜弹膛**（+60%冰伤，+60%多重射击）  \\n3. **膛线**（+165%基础伤害）  \\n4. **关键延迟**（+200%暴击伤害，-20%射速）  \\n5. **弱点专精**（+150%暴击伤害）  \\n6. **雷火**（+90%电伤）  \\n7. **电冲触点**（+90%火伤）  \\n8. **猎人军备**（+60%多重射击，触发连击）  \\n\\n**特点**：  \\n- **暴击率26% → 74%**（近战连击触发猎人军备后可达100%以上）  \\n- **暴击伤害6.6x**，单发子弹可轻松破百万伤害，适合秒杀高护甲Boss（如三傻、钢铁之路头目）。  \\n- 元素组合为**电+火=辐射**，对Grineer头目和Sentient效果极佳。\\n\\n---\\n\\n### **灵活元素流（任务适配）**\\n**核心Mod**（替换部分）：\\n- 将**电冲触点+雷火**替换为：  \\n  - **恶性扩散**（+60%毒素，+60%触发率）  \\n  - **病原弹头**（+90%毒素）  \\n  - **白霜弹膛**保留，组合为**毒+冰=病毒**，削弱敌人生命值上限，适合持续输出场景（如生存任务）。  \\n- 可选**加速扳机**（+60%射速）改善手感，替换猎人军备。\\n\\n---\\n\\n### **极化与操作建议**：\\n1. **极化**：至少2次，推荐V（Madurai）和-（Naramon）极性，适配高阶Mod。  \\n2. **射速补偿**：执法者射速较慢，可通过指挥官技能（如虚空突显）或队友加速Buff（如Volt盾）改善。  \\n3. **元素调整**：  \\n   - **Grineer/Corrupted**：辐射（电+火）或病毒（毒+冰）  \\n   - **Corpus**：磁力（电+冰）+ 毒  \\n   - **Infested**：腐蚀（电+毒） + 火  \\n\\n---\\n\\n### **紫卡建议**（可选）：\\n- 优先词条：暴击伤害、基础伤害、多重射击。  \\n- 负属性可接受：装填速度、弹匣容量（对单发爆发影响小）。\\n\\n根据你的游戏阶段和资源，可逐步替换为镀层/Prime Mod（如镀层地狱弹膛）。如果需要更详细的调整，可以告诉我你的具体使用场景！\",\"reasoning_content\":\"嗯，用户让我帮忙生成一个《Warframe》中执法者的配卡。首先，我需要确认执法者的基本信息，比如它的类型是主武器还是副武器，有什么特性，以及用户可能的游戏风格。执法者是一把霰弹枪，由Archwing任务中的Grineer敌人掉落，属于高伤害但射速较慢的类型。\\n\\n接下来，用户可能希望最大化伤害，或者考虑装填速度、射速等。我需要回忆常用的霰弹枪Mod，比如地狱弹膛、白霜弹膛，还有基础的伤害Mod如膛线。另外，执法者的暴击和触发几率如何？如果暴击率不错，可能需要装关键延迟、弱点专精等暴击相关Mod。如果触发几率高，则可以考虑元素Mod和状态触发。\\n\\n不过，执法者的暴击几率是26%，算是较高的，所以暴击流可能更有效。触发几率只有6%，所以可能不太适合纯触发流。因此，配卡应该优先提升暴击和基础伤害。\\n\\n然后，考虑用户的段位，是否有限制使用高容量Mod的情况？比如，膛线、地狱弹膛可能需要较高的容量，用户是否已经极化过武器？可能需要建议极化几次，安装Forma来适应高阶Mod。\\n\\n另外，元素组合方面，根据敌人类型选择，比如病毒+火对付Grineer，腐蚀+火对付Infested，或者磁力+毒对付Corpus。需要提醒用户根据任务调整元素组合。\\n\\n可能还需要考虑射速和装填速度，执法者的射速较慢，装填时间较长，所以加速扳机和猎人的军备可能有用。不过要注意Mod的容量是否足够，可能需要极化。\\n\\n总结下来，核心Mod应该是基础伤害、多重射击、暴击率和暴击伤害，元素伤害根据情况调整，射速和装填速度Mod作为可选。另外，如果有Prime版本或者特殊Mod，是否需要考虑？比如镀层Mod或者牺牲Mod，但用户可能没有，所以先推荐常规Mod。\\n\\n最后，需要给出两种配置，一种纯暴击，另一种混合触发，或者根据不同任务调整。同时提醒用户极化建议和元素搭配的灵活性。确保Mod名称正确，比如“地狱弹膛”是否正确，或者是否有其他名称，比如“白霜弹膛”可能是指“白霜霰弹”？需要确认Mod的正确名称，避免混淆。\\n\\n可能用户是新手，不太了解极化，所以需要简单说明极化的重要性，比如安装Forma来调整极性，减少Mod容量消耗。同时，执法者的高基础伤害，暴击流更适合，所以配置以暴击为主。\\n\\n检查是否有遗漏的Mod，比如“雷筒”增加弹匣容量，但执法者弹匣只有4发，可能不需要，还是优先伤害和射速更好。装填速度Mod如“爆发装填”是否有必要，但可能容量吃紧，可以放在可选部分。\\n\\n最终配卡应该包括：地狱弹膛、白霜弹膛、膛线、关键延迟、弱点专精、雷火、电冲触点、猎人军备，或者替换元素Mod。极化建议使用V和-极性，可能需要两次极化。\",\"role\":\"assistant\"}}],\"created\":1740721184,\"model\":\"deepseek-reasoner\",\"system_fingerprint\":\"fp_5417b77867_prod0225\",\"object\":\"chat.completion\",\"usage\":{\"completion_tokens\":1317,\"prompt_tokens\":20,\"prompt_cache_hit_tokens\":0,\"prompt_cache_miss_tokens\":20,\"total_tokens\":1337,\"completion_tokens_details\":{\"reasoning_tokens\":650}}}\n")
//                        .toBean(DeepSeekChatCompletionsVO.class);
        System.out.println(deepSeekChatCompletionsVO);
        File file = new File("src/main/resources/deepSeek/deepSeek.md");
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write("问：" + deepSeekChatCompletionsQO.getMessages().get(0).getContent() + "<br>"
                + "思考：" + deepSeekChatCompletionsVO.getChoices().get(0).getMessage().getReasoningContent() + "<br>"
                + "答：" + deepSeekChatCompletionsVO.getChoices().get(0).getMessage().getContent());
    }

    @Test
    public void testXpSaveRedis() {
        List<String> exList = Arrays.asList("1: 0","2: 33","3: 76","4: 132","5: 202","6: 286","7: 386","8: 503","9: 637","10: 791","11: 964","12: 1,159","13: 1,377","14: 1,620","15: 1,891","16: 2,192","17: 2,525","18: 2,893","19: 3,300","20: 3,750","21: 4,247","22: 4,795","23: 5,400","24: 6,068","25: 6,805","26: 7,618","27: 8,517","28: 9,508","29: 10,604","30: 11,814","31: 13,151","32: 14,629","33: 16,262","34: 18,068","35: 20,064","36: 22,271","37: 24,712","38: 27,411","39: 30,396","40: 33,697","41: 37,346","42: 41,381","43: 45,842","44: 50,773","45: 56,222","46: 62,243","47: 68,895","48: 76,242","49: 84,355","50: 93,311","51: 103,195","52: 114,100","53: 126,127","54: 139,390","55: 154,009","56: 170,118","57: 187,863","58: 207,403","59: 228,914","60: 252,584","61: 278,623","62: 307,256","63: 338,731","64: 373,318","65: 411,311","66: 453,030","67: 498,824","68: 549,074","69: 604,193","70: 664,632","71: 730,881","72: 803,472","73: 882,985","74: 970,050","75: 1,065,351","76: 1,169,633","77: 1,283,701","78: 1,408,433","79: 1,544,780","80: 1,693,774","81: 1,856,536","82: 2,034,279","83: 2,228,321","84: 2,440,088","85: 2,671,127","86: 2,923,113","87: 3,197,861","88: 3,497,335","89: 3,823,663","90: 4,179,145","91: 4,566,274","92: 4,987,741","93: 5,446,463","94: 5,945,587","95: 6,488,521","96: 7,078,945","97: 7,720,834","98: 8,418,485","99: 9,176,537","100: 10,000,000","101: 11,404,976","102: 12,904,567","103: 14,514,400","104: 16,242,080","105: 18,095,702","106: 20,083,886","107: 22,215,808","108: 24,501,230","109: 26,950,540","110: 29,574,787","111: 32,385,721","112: 35,395,838","113: 38,618,420","114: 42,067,584","115: 45,758,332","116: 49,706,603","117: 53,929,328","118: 58,444,489","119: 63,271,179","120: 68,429,670","121: 73,941,479","122: 79,829,440","123: 86,117,783","124: 92,832,214","125: 100,000,000","126: 114,406,130","127: 130,118,394","128: 147,319,656","129: 166,147,618","130: 186,752,428","131: 209,297,771","132: 233,962,072","133: 260,939,787","134: 290,442,814","135: 322,702,028","136: 357,968,938","137: 396,517,495","138: 438,646,053","139: 484,679,494","140: 534,971,538","141: 589,907,252","142: 649,905,763","143: 715,423,218","144: 786,955,977","145: 865,044,093","146: 950,275,074","147: 1,043,287,971","148: 1,144,777,804","149: 1,255,500,373","150: 1,376,277,458","151: 1,508,002,470","152: 1,651,646,566","153: 1,808,265,285","154: 1,979,005,730","155: 2,165,114,358","156: 2,367,945,418","157: 2,588,970,089","158: 2,829,786,381","159: 3,092,129,857","160: 3,377,885,250","161: 3,689,099,031","162: 4,027,993,033","163: 4,396,979,184","164: 4,798,675,471","165: 5,235,923,207","166: 5,711,805,728","167: 6,229,668,624","168: 6,793,141,628","169: 7,406,162,301","170: 8,073,001,662","171: 8,798,291,902","172: 9,587,056,372","173: 10,444,742,007","174: 11,377,254,401","175: 12,390,995,728","176: 13,492,905,745","177: 14,690,506,120","178: 15,991,948,361","179: 17,406,065,609","180: 18,942,428,633","181: 20,611,406,335","182: 22,424,231,139","183: 24,393,069,640","184: 26,531,098,945","185: 28,852,589,138","186: 31,372,992,363","187: 34,109,039,054","188: 37,078,841,860","189: 40,302,007,875","190: 43,799,759,843","191: 47,595,067,021","192: 51,712,786,465","193: 56,179,815,564","194: 61,025,256,696","195: 66,280,594,953","196: 71,979,889,960","197: 78,159,982,881","198: 84,860,719,814","199: 92,125,192,822","200: 100,000,000,000");
        Map<Integer, String> gradeExMap = new HashMap<>();
        for (String ex : exList) {
            String[] exSplit = ex.split(": ");
            gradeExMap.put(Integer.valueOf(exSplit[0]), exSplit[1].replaceAll(",", ""));
        }
        System.out.println(JSONUtil.toJsonStr(gradeExMap));
        redisTemplate.delete(RedisKeyInterface.GRADE_XP);
        redisTemplate.opsForHash().putAll(RedisKeyInterface.GRADE_XP, gradeExMap.entrySet()
                .stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(
                        a -> String.valueOf(a.getKey()),
                        Map.Entry::getValue,
                        (e1, e2) -> e1, // 合并函数（这里不需要合并，因为不会有重复键）
                        LinkedHashMap::new)));
    }

    @Test
    public void testSaveRedis() {
        long groupId = 1L;
        long userId = 2L;
        String fishName = "鱼1";
        String quantityObj = (String) redisTemplate.opsForHash().get(RedisKeyInterface.ITEM + groupId + userId, fishName);
        Integer quantity = quantityObj == null ? 0: Integer.parseInt(quantityObj);
        quantity++;
        redisTemplate.opsForHash().put(RedisKeyInterface.ITEM + groupId + userId, fishName, String.valueOf(quantity));
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(RedisKeyInterface.ITEM + groupId + userId);
        System.out.println(JSONUtil.toJsonStr(entries));
    }

    @Resource
    private JmHandler jmHandler;

    @Test
    public void testRunPython() throws IOException, InterruptedException {
        EventReportingDTO.Message.Data data = new EventReportingDTO.Message.Data();
        data.setText("jm 1026275");
        jmHandler.handler(data, 938354542L);
    }

    @Test
    public void testCacheArbitrationInfo() throws IOException {
        redisTemplate.delete(RedisKeyInterface.WARFRAME_ARBITRATION_INFO);
        File file = new File("C:\\Users\\admin\\Downloads\\仲裁.xlsx");
        List<ArbitrationInfoDTO> objects = EasyExcel.read(file).head(ArbitrationInfoDTO.class).sheet().doReadSync();
        System.out.println(objects);
        objects.forEach(o -> {
            o.setTime(DateUtil.parse(o.getTime()).toString("yyyy-MM-dd HH:mm:ss"));
        });
        System.out.println(objects);
        redisTemplate.opsForValue().set(RedisKeyInterface.WARFRAME_ARBITRATION_INFO, objects.toString());
    }

    @Resource
    private ArbitrationJob arbitrationJob;

    @Test
    public void testArbitrationJob() {
        arbitrationJob.arbitration();
    }

}
